#!/usr/bin/env python

class KalTokenizer(object):
    escape_map = {'n':'\n','r':'\r','t':'\t'}
    def __init__(self,kal_code):
        self.kal_code = kal_code
        self.char_index = 0
        self.line_no = 1
        self.column_no = 1
        self.token_type = 'UNKNOWN'
    def __iter__(self):
        return self
    def is_alpha(self,c):
        return (c >= 'A' and c <= 'Z') or (c >= 'a' and c <= 'z')
    def is_numeric(self,c):
        return c >= '0' and c <= '9'
    def is_whitespace(self,c):
        return c in (' ','\t','\r','\n')
    def eat_whitespace(self):
        while self.char_index < len(self.kal_code) and self.is_whitespace(self.kal_code[self.char_index]):
            self.char_index += 1
        if self.kal_code[self.char_index] == '#':
            while self.char_index < len(self.kal_code) and self.kal_code[self.char_index] != '\n':
                self.char_index += 1
            self.eat_whitespace()
    def unescape(self,s):
        escape = False
        rv = ""
        for c in s:
            if escape:
                if c in self.escape_map:
                    rv += self.escape_map[c]
                else:
                    rv += c
            elif c == '\\':
                escape = True
            else:
                rv += c
        return rv
    def eof(self):
        return self.char_index >= code_len
    def next(self):
        code_len = len(self.kal_code)
        
        self.eat_whitespace()
        
        if self.char_index >= code_len:
            raise StopIteration
        
        self.token_type = 'UNKNOWN'
        start_index = self.char_index
        while self.char_index < code_len:
            c = self.kal_code[self.char_index]
            if self.token_type == 'UNKNOWN':
                if self.is_alpha(c):
                    self.token_type = 'NAME'
                elif self.is_numeric(c):
                    self.token_type = 'INTEGER'
                elif c == '"' or c == "'":
                    self.token_type = 'STRING'
                    quote_type = c
                    start_index = start_index + 1
            elif self.token_type == 'NAME':
                if self.is_whitespace(c):
                    break
            elif self.token_type == 'INTEGER':
                hex_token = False
                if c == '.' and hex_token == False:
                    self.token_type = 'FLOAT'
                elif c == 'x' and  start_index + 1 == self.char_index and self.kal_code[self.char_index1] == '0':
                    hex_token = True
                elif not self.is_numeric(c):
                    break
            elif self.token_type == 'FLOAT':
                if not self.is_numeric(c) and c not in ('a','b','c','d','e','f','A','B','C','D','E','F'):
                    break
            elif self.token_type == 'STRING':
                escaping = False
                if c == '\\':
                    escaping = True